<?php

namespace App\Services;

use App\Jobs\DealExcelByPython;
use App\Jobs\MergeExcel;
use App\Models\DownloadJob;
use App\Models\PartCompany;
use App\Models\Project;
use App\Models\ProjectClassify;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Symfony\Component\Process\Process;

class DownloadJobService extends BaseService
{
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * 获取列表
     */
    public function getList($request, $perPage)
    {
        $thisQuery = DownloadJob::query()
            ->where('user_id', user_id())
            ->where('company_id', company_id())
            ->where('created_at', '>', Carbon::now()->subDays(3))
            ->select('id', 'username', 'part_company_id', 'book_title_ids', 'task_name', 'detail', 'file_count',
                'download_url', 'dir_storage_path', 'type', 'status', 'is_zip', 'is_display', 'created_at', 'updated_at')
            ->orderByDesc('id');

        if ($request->filled('status')) {
            $status = $request->input('status');
            $thisQuery->where('status', $status);
        }
        if ($request->filled('keyword')) {
            $keyword = $request->input('keyword');
            $thisQuery->where('task_name', 'like', "%{$keyword}%")->orWhere('username', 'like', "%{$keyword}%");
        }
        $list = $thisQuery->paginate($perPage);
        if ($list->isEmpty()) return [];
        $list = $list->toArray();
        foreach ($list['data'] as &$val) {
            $needCount              = $val['file_count'];
            $val['need_count']      = $val['file_count'] . '个文件';
            $val['completed_count'] = 0;
            $dir                    = $val['dir_storage_path'];
            $hadCompleted           = $this->getFileCount($dir);
            $val['completed_count'] = $hadCompleted . '个文件';
            $status  = $val['status'];
            if ($status == 1) { //下载中
                if ($val['created_at'] < Carbon::parse()->subMinutes(60)) {
                    DownloadJob::query()->where('id', $val['id'])->update(['status' => 4]); //如果已下载超过60分钟，更新为失败
                } else {
                    $val['duration'] = date('i分s秒', time() - strtotime($val['created_at']));
                }
            } elseif ($status == 3) { //已完成
                $val['duration'] = date('i分s秒', strtotime($val['updated_at']) - strtotime($val['created_at']));
                $val['completed_count'] = $val['file_count'] . '个文件';
            } else {
                $val['duration'] = date('i分s秒', time() - strtotime($val['created_at']));
            }
            if ($val['status'] != 2 && $val['status'] != 4 && ($hadCompleted == $val['file_count'] && empty($val['download_url']))) {
                if ($val['is_zip'] && $val['is_display']) { //如果需要压缩成zip
                    $downloadDir = CommonService::createZip('storage/' . $dir);
                    DownloadJob::query()->where('id', $val['id'])->update(['status' => 3, 'download_url' => $downloadDir, 'is_display'=>1]);
                } else {
                    DownloadJob::query()->where('id', $val['id'])->update(['status' => 2]); //合成中
                    $projectId = PartCompany::query()->where('id', $val['part_company_id'])->value('project_id');
                    self::dealExcelByPython($projectId, $val['id'], $dir, $val['type']);
                }
            }
            $val['percentage'] = round(($hadCompleted / $needCount) * 100);
            $val['basename']   = pathinfo($val['download_url'])['basename'];
            $val['created_at'] = date('m-d H:i', strtotime($val['created_at']));
        }

        $data = $list['data'];
        $tableData = array_filter($data, function ($data) {
            return $data['is_display'] == 1;
        });
        $list['data']  = array_values($tableData);
        $list['total'] = count($tableData); //过滤后要重新计算数据条数
        $allStatus = array_column($list['data'], 'status');
        $list['sendApiRequest'] = (in_array(1, $allStatus) || in_array(2, $allStatus)) ? 1 : 0; //如果有下载中的数据，就继续请求，前端有 setInterval;

        return $this->removeNoUsedPageParams($list);
    }

    /**
     * 获取文件数量
     * @param $dir
     * @return int
     * @author: lxk
     * @date: 2024/3/4 15:18
     */
    public function getFileCount($dir): int
    {
        $filesArr = Storage::files('public/' . $dir);

        return count($filesArr);
    }

    /**
     * 使用Python处理excel格式
     *
     * @author: lxk
     * @date: 2025-02-20 17:36
     */
    public static function dealExcelByPython($projectId, $downloadJobId, $dir, $type, $isZip = 0)
    {
        $combinationId = Project::query()->where('id', $projectId)->value('combination_id');
        if ($type == 1) { //导出卷内目录
            if ($combinationId == 2) {
                if (in_array($projectId, [5,15,16])) { //京石公司8号文专用
                    $pythonScript = 'python_script/8_catalog_js.py';
                } else {
                    $pythonScript = 'python_script/8_catalog.py';
                }
            } elseif ($combinationId == 3) {
                $pythonScript = 'python_script/ly_catalog.py';
            } elseif ($combinationId == 4) {
                $pythonScript = 'python_script/bz_29_catalog.py';
            } else {
                $pythonScript = 'python_script/29_catalog.py';
            }
        } else { //导出全引目录
            if ($projectId == 5) {
                $pythonScript = 'python_script/ly_index.py';
            } else {
                $pythonScript = 'python_script/29_index.py';
            }
        }
        $pythonEnv = self::getPythonEnv();
        $process = new Process([$pythonEnv, $pythonScript, 'storage/' . $dir, 3000, $isZip]); //交给python进行合成
        $process->setTimeout(7200); //python脚本执行超时时间秒
        $process->run();
        if (!$process->isSuccessful()) {
            info('python处理excel失败---' . $process->getErrorOutput());
            DownloadJob::query()->where('id', $downloadJobId)->update(['status' => 4]);
        } else {
            $downloadDir = $process->getOutput();
            $downloadDir = preg_replace("/\r?\n/", "", $downloadDir); //去掉可能的换行符 如 \n
            DownloadJob::query()->where('id', $downloadJobId)->update(['status' => 3, 'download_url' => config('site.domain') . $downloadDir]);
        }
    }

    /**
     * 获取python的执行环境
     *
     * @return string
     * @author: lxk
     * @date: 2025-07-02 17:43
     */
    public static function getPythonEnv() : string
    {
        $pythonEnv = '/www/server/pyporject_evn/versions/3.10.16/bin/python3'; //生产环境
        if (config('site.domain') != 'https://tielu.qichenglantai.com/') {  //开发环境
            $pythonEnv = 'D:\phpstudy_pro\WWW\newRailway\public\python_script\venv\Scripts\python.exe';
        }

        return $pythonEnv;
    }

    /**
     * 合成封面
     */
    public function mergeExcel($dirStorage)
    {
        $files = File::allFiles($dirStorage);
        if (empty($files)) return '';
        asort($files, SORT_STRING | SORT_FLAG_CASE | SORT_NATURAL); // 对值排序
        $files      = array_values($files);
        $firstExcel = $dirStorage . '/' . $files[0]->getFilename();
        $baseExcel  = IOFactory::load($firstExcel);
        unset($files[0]);
        foreach ($files as $file) {
            $loadExcel = IOFactory::load($dirStorage . '/' . $file->getFilename());
            $baseExcel->addExternalSheet($loadExcel->getActiveSheet());
        }
        $endSlashPos    = strrpos($dirStorage, '/');
        $mergedFileName = substr($dirStorage, $endSlashPos) . ".xlsx";
        $newDirStorage  = substr($dirStorage, 0, $endSlashPos);
        $downloadDir    = $newDirStorage . $mergedFileName;

        $writer = IOFactory::createWriter($baseExcel, 'Xlsx');
        $writer->save($downloadDir);

        $needDelDir = str_replace('storage', '/public', $dirStorage);
        Storage::deleteDirectory($needDelDir);

        return config('site.domain') . $downloadDir;
    }

    /**
     * 新增/更新 数据
     */
    public function addNewDataD($partCompanyId, $projectClassifyId, $bookTitleIds, $dirStorage, $fileCount)
    {
        $downloadJob                      = new DownloadJob();
        $downloadJob->company_id          = '999';
        $downloadJob->part_company_id     = $partCompanyId;
        $downloadJob->project_classify_id = $projectClassifyId;
        $downloadJob->file_count          = $fileCount;
        $downloadJob->book_title_ids      = implode(',', $bookTitleIds);
        $downloadJob->user_id             = '999';
        $downloadJob->username            = '赵晶';
        $downloadJob->task_name           = '导出卷内目录';
        $downloadJob->detail              = "刷格式";
        $downloadJob->dir_storage_path    = $dirStorage;
        $downloadJob->download_url        = '';
        $downloadJob->status              = 1;
        $downloadJob->save();

        return $downloadJob->id;
    }

    /**
     * 新增/更新 数据
     * is_zip = 1，is_display = 1 需要打包成zip文件，进行显示
     * is_zip = 1，is_display = 0 需要打包成zip文件，不显示
     * is_zip = 0，直接显示
     */
    public function addNewData($partCompanyId, $projectClassifyId, $bookTitleIds, $dirName, $fileCount, $type = 1, $isZip = 0, $isDisplay = 0)
    {
        CommonService::createDir($dirName);
        $downloadJob                      = new DownloadJob();
        $downloadJob->company_id          = company_id() ?: 0;
        $downloadJob->part_company_id     = $partCompanyId;
        $downloadJob->project_classify_id = $projectClassifyId;
        $downloadJob->file_count          = $fileCount;
        $downloadJob->book_title_ids      = $bookTitleIds ? implode(',', $bookTitleIds) : '';
        $downloadJob->user_id             = user_id();
        $downloadJob->username            = user() ? user()->nickname : '';
        $downloadJob->task_name           = $type == 1 ? '导出【卷内】目录' : '导出【全引】目录';
        $downloadJob->detail              = !($isZip && $isDisplay) ? str_replace('excels/', '', $dirName) . '.xlsx' : str_replace('excels/', '', $dirName) . '.zip';
        $downloadJob->dir_storage_path    = $dirName;
        $downloadJob->download_url        = '';
        $downloadJob->status              = 1;
        $downloadJob->type                = $type; //1卷内 2全引
        $downloadJob->is_zip              = $isZip; //0-单独excel文件，,1-打包的zip文件
        $downloadJob->is_display          = $isDisplay;
        $downloadJob->save();

        return $downloadJob->id;
    }

    /**
     * 获取案卷序号 （总批量范围）
     */
    public static function getDirName($obj, $ids)
    {
        $projectClassifyId   = $obj->where('id', $ids[0])->value('project_classify_id');
        $projectClassifyName = ProjectClassify::query()->where('id', $projectClassifyId)->value('title');
        $serialNos           = $obj->whereIn('id', $ids)->orderBy('serial_no')->pluck('serial_no')->toArray();
        if (str_contains($projectClassifyName, '/')) {
            $projectClassifyName = str_replace('/', '_', $projectClassifyName);
        }
        if (str_contains($projectClassifyName, '#')) {
            $projectClassifyName = str_replace('#', '井', $projectClassifyName);
        }
        return $projectClassifyName . '_案卷【' . min($serialNos) . '~' . max($serialNos) . '】';
    }


    /**
     * 获取案卷序号 （分批范围）
     */
    public static function getChildSerialNosD($obj, $ids)
    {
        $archivesNos = $obj->whereIn('id', $ids)->orderBy('id')->pluck('archives_no')->toArray();
        $serialNos   = [];
        foreach ($archivesNos as $archivesNo) {
            $archivesPart = CommonService::getArchivesPart($archivesNo);
            $serialNos[]  = $archivesPart['ext'];
        }

        return '【' . min($serialNos) . '~' . max($serialNos) . '】';
    }

    /**
     * 获取案卷序号 （分批范围）
     */
    public static function getChildSerialNos($obj, $ids)
    {
        $serialNos = $obj->whereIn('id', $ids)->orderBy('serial_no')->pluck('serial_no')->toArray();

        return '【' . min($serialNos) . '~' . max($serialNos) . '】';
    }

}
